/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Parser;


import Mapper.Mapper;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

/**
 *
 * @author Nicolás Loaiza Cardona (nicoloaiza@gmail.com)
 */
public class Processor<T> {
    private ArrayList<String> header;
    private String delimiter;
    private String file;
    private InputStream stream;

    public void setStream(InputStream stream) {
        this.stream = stream;
    }

    public InputStream getStream() {
        return stream;
    }
    private int headerLineNumber;
    private Class type;

    
    /**
    * Constructor
    * @param  delimiter  delimiter for the csv file
    * @param  file path for the csv file.
    * @param  headerLineNumber  line number for the header
    * @param  type Class for the object to be loaded with the data
    */         
    public Processor(String delimiter, String file, int headerLineNumber, Class type) {
        this.delimiter = delimiter;
        this.file = file;
        this.headerLineNumber = headerLineNumber;  
        //File archivo = new File(classFile);
        this.type = type;
        this.header = new ArrayList<String>();
    }
    
    /**
    * Constructor
    * @param  delimiter  delimiter for the csv file
    * @param  stream InputStream for the csv file.
    * @param  headerLineNumber  line number for the header
    * @param  type Class for the object to be loaded with the data
    */          
    public Processor(String delimiter, InputStream stream, int headerLineNumber, Class type) {
        this.delimiter = delimiter;
        this.file = null;
        this.stream = stream;
        this.headerLineNumber = headerLineNumber;  
        this.type = type;
        this.header = new ArrayList<String>();
    }
    
    public ArrayList<String> getHeader() {
        return header;
    }

    public String getDelimiter() {
        return delimiter;
    }

    public String getFile() {
        return file;
    }
    public Class getObjectClass() {
        return this.type;
    }

    public int getHeaderLineNumber() {
        return headerLineNumber;
    }

    public void setHeader(ArrayList<String> cabecera) {
        this.header = cabecera;
    }

    public void setDelimiter(String delimitador) {
        this.delimiter = delimitador;
    }

    public void setFile(String file) {
        this.file = file;
    }

    public void setHeaderLineNumber(int headerLineNumber) {
        this.headerLineNumber = headerLineNumber;
    }  

    public void setObjectClass(Class clase) {
        this.type = clase;
    }

    public Processor()
    {}
    
    /**
    * Returns an  ArrayList<Object> that contains the mapped objects. 
    * <p> */  
    public ArrayList<T> Process()
    {
         ArrayList<T> objects = new ArrayList<T>();
         ArrayList<HashMap> maps = Analize();
         if(maps != null)
         {
             if(maps.size() > 0)
             {
                 Mapper mapper = new Mapper<T>();
                 objects = mapper.Map(maps,this.type);
             }
         }
         return objects;
    }
      
    /**
    * Returns an  ArrayList<HashMap> that contains the data with their respective header. 
    * <p> */  
    private ArrayList<HashMap> Analize()
    {
        String source = "áàäéèëíìïóòöúùuñÁÀÄÉÈËÍÌÏÓÒÖÚÙÜÑçÇ";
        String ascii = "aaaeeeiiiooouuunAAAEEEIIIOOOUUUNcC";        
        ArrayList<HashMap> maps = new ArrayList<HashMap>();
        try {
            FileInputStream fis = null;
            if(this.file != null)
            {
                fis = new FileInputStream(this.file);
            }
            InputStreamReader is;
            try {
                BufferedReader in;
                if(this.file != null)
                {
                    is = new InputStreamReader(fis, "ISO-8859-1");
                    in = new BufferedReader(is);            
                }
                else
                {
                    is = new InputStreamReader(stream, "ISO-8859-1");
                    in = new BufferedReader(is);       
                }
                if(this.headerLineNumber > 1)
                {
                    int currentline = 1;
                    while(currentline < this.headerLineNumber)
                    {
                        try {
                            in.readLine();
                            currentline++;
                        } catch (IOException ex) {}
                    }
                }
                try {
                    String line = in.readLine();
                    String[] fields = line.split(this.delimiter);
                    for(int i = 0; i<fields.length; i++)
                    {
                        fields[i] = fields[i].trim();
                        String output = fields[i];
                        for (int j = 0; j < source.length(); j++) {
                            output = output.replace(source.charAt(j), ascii.charAt(j));
                        }  
                        output = output.replaceAll("[.|/|']", "");
                        fields[i] = ToCamelCase(output);
                    }
                    header.addAll(Arrays.asList(fields));
                    while ((line = in.readLine()) != null)   {
                        maps.add(Parser.Parse(line,header,delimiter));
                    }
                } catch (IOException ex) {

                }
            } catch (UnsupportedEncodingException ex) {
            }  
            finally
            {
                try {
                    if(this.file != null)
                        fis.close();
                } catch (IOException ex) {
                }
            }
        } catch (FileNotFoundException ex) {
            
        }    
        return maps;
    }   
    
 
    /**
    * Returns an  String converted to Camel case 
    * <p> */      
    private String ToCamelCase(String base)
    {
        StringBuilder sb = new StringBuilder();
        String[] valores = base.split(" "); 
        for (String s : valores) {
            if(s.length() > 0)
            {
                sb.append(Character.toUpperCase(s.charAt(0)));
                if (s.length() > 1) {
                    sb.append(s.substring(1, s.length()).toLowerCase());
                }
            }
        }        
        return sb.toString();
    }
}
